package com.hanbo.flymouse.hid

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.bluetooth.*
import android.bluetooth.BluetoothHidDeviceAppQosSettings.*
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.util.Log
import android.widget.Toast
import androidx.core.app.NotificationCompat

class HidPeripheralService : Service() {
    private var bluetoothAdapter: BluetoothAdapter? = null
    private var hidDevice: BluetoothHidDevice? = null
    private var connectedHost: BluetoothDevice? = null

    override fun onCreate() {
        super.onCreate()
        startForegroundWithNotification()
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
        val manager = getSystemService(BLUETOOTH_SERVICE) as BluetoothManager
        val profileListener = object : BluetoothProfile.ServiceListener {
            override fun onServiceConnected(profile: Int, proxy: BluetoothProfile?) {
                if (profile == BluetoothProfile.HID_DEVICE) {
                    hidDevice = proxy as BluetoothHidDevice
                    registerApp()
                }
            }
            override fun onServiceDisconnected(profile: Int) {
                if (profile == BluetoothProfile.HID_DEVICE) hidDevice = null
            }
        }
        manager.adapter.getProfileProxy(this, profileListener, BluetoothProfile.HID_DEVICE)
    }

    private fun registerApp() {
        val sdp = BluetoothHidDeviceAppSdpSettings(
            "Fly Mouse",
            "Phone acts as a Bluetooth Mouse",
            "Hanbo",
            BluetoothHidDevice.SUBCLASS1_COMBO,
            HID_REPORT_DESC
        )
        val inQos = BluetoothHidDeviceAppQosSettings(SERVICE_BEST_EFFORT, 800, 9, 0, 11250, 11250)
        val outQos = BluetoothHidDeviceAppQosSettings(SERVICE_BEST_EFFORT, 800, 9, 0, 11250, 11250)
        hidDevice?.registerApp(sdp, inQos, outQos, mainExecutor, callback)
    }

    private val callback = object : BluetoothHidDevice.Callback() {
        override fun onAppStatusChanged(pluggedDevice: BluetoothDevice?, registered: Boolean) {
            Log.i(TAG, "HID app registered=$registered device=$pluggedDevice")
            Toast.makeText(applicationContext, if (registered) "HID已注册" else "HID未注册", Toast.LENGTH_SHORT).show()
            if (registered) {
                tryConnectToDefaultBondedHost()
            }
        }
        override fun onConnectionStateChanged(device: BluetoothDevice?, state: Int) {
            val s = when (state) {
                BluetoothProfile.STATE_CONNECTED -> "已连接"
                BluetoothProfile.STATE_CONNECTING -> "连接中"
                BluetoothProfile.STATE_DISCONNECTED -> "已断开"
                BluetoothProfile.STATE_DISCONNECTING -> "断开中"
                else -> "未知"
            }
            Log.i(TAG, "HID $s host=$device")
            Toast.makeText(applicationContext, "HID $s", Toast.LENGTH_SHORT).show()
            if (state == BluetoothProfile.STATE_CONNECTED) connectedHost = device
            if (state == BluetoothProfile.STATE_DISCONNECTED) connectedHost = null
        }
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        when (intent?.action) {
            ACTION_START -> { /* 已在 onCreate 注册 */ }
            ACTION_MOVE -> {
                val dx = intent.getIntExtra(KEY_DX, 0)
                val dy = intent.getIntExtra(KEY_DY, 0)
                Log.d(TAG, "MOVE received dx=$dx dy=$dy host=${connectedHost != null}")
                // 简单放大倍数，提升可见度
                sendRelativeMouse(dx * 2, dy * 2)
            }
            ACTION_CLICK_LEFT -> {
                Log.d(TAG, "LEFT CLICK received")
                sendMouseClick(1) // 左键
            }
            ACTION_CLICK_RIGHT -> {
                Log.d(TAG, "RIGHT CLICK received")
                sendMouseClick(2) // 右键
            }
            ACTION_SCROLL -> {
                val dx = intent.getIntExtra(KEY_DX, 0)
                val dy = intent.getIntExtra(KEY_DY, 0)
                Log.d(TAG, "SCROLL received dx=$dx dy=$dy")
                sendMouseScroll(dx, dy)
            }
            ACTION_CONNECT_DEFAULT -> {
                tryConnectToDefaultBondedHost()
            }
        }
        return START_STICKY
    }

    private fun tryConnectToDefaultBondedHost() {
        val adapter = bluetoothAdapter ?: return
        val bonded = adapter.bondedDevices
        if (bonded.isNullOrEmpty()) {
            Log.w(TAG, "没有已配对的主机，无法自动连接")
            Toast.makeText(applicationContext, "无已配对主机", Toast.LENGTH_SHORT).show()
            return
        }
        val host = bonded.firstOrNull()
        if (host == null) {
            Toast.makeText(applicationContext, "无可用主机", Toast.LENGTH_SHORT).show()
            return
        }
        val dev = hidDevice
        if (dev == null) {
            Toast.makeText(applicationContext, "HID未就绪", Toast.LENGTH_SHORT).show()
            return
        }
        Log.i(TAG, "尝试连接默认主机: $host")
        dev.connect(host)
    }

    override fun onDestroy() {
        connectedHost = null
        hidDevice?.unregisterApp()
        super.onDestroy()
    }

    override fun onBind(intent: Intent?): IBinder? = null

    private fun startForegroundWithNotification() {
        val channelId = "hid_service"
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val nm = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            val channel = NotificationChannel(channelId, "HID Service", NotificationManager.IMPORTANCE_LOW)
            nm.createNotificationChannel(channel)
        }
        val notif: Notification = NotificationCompat.Builder(this, channelId)
            .setContentTitle("Fly Mouse 运行中")
            .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth)
            .build()
        startForeground(1, notif)
    }

    fun sendRelativeMouse(dx: Int, dy: Int, buttons: Int = 0) {
        val host = connectedHost ?: run {
            Log.w(TAG, "未连接主机，丢弃鼠标事件 dx=$dx dy=$dy")
            return
        }
        val report = byteArrayOf(
            buttons.toByte(),
            dx.coerceIn(-127, 127).toByte(),
            dy.coerceIn(-127, 127).toByte(),
            0
        )
        val ok = hidDevice?.sendReport(host, REPORT_ID_MOUSE, report) ?: false
        Log.d(TAG, "sendReport id=$REPORT_ID_MOUSE len=${report.size} ok=$ok")
    }

    fun sendMouseClick(button: Int) {
        val host = connectedHost ?: run {
            Log.w(TAG, "未连接主机，丢弃点击事件 button=$button")
            return
        }
        // 按下按钮
        sendRelativeMouse(0, 0, button)
        // 立即释放按钮
        sendRelativeMouse(0, 0, 0)
        Log.d(TAG, "Mouse click button=$button")
    }

    fun sendMouseScroll(dx: Int, dy: Int) {
        val host = connectedHost ?: run {
            Log.w(TAG, "未连接主机，丢弃滚轮事件 dx=$dx dy=$dy")
            return
        }
        val report = byteArrayOf(
            0, // 无按钮
            0, // 无X移动
            0, // 无Y移动
            dy.coerceIn(-127, 127).toByte() // 滚轮
        )
        val ok = hidDevice?.sendReport(host, REPORT_ID_MOUSE, report) ?: false
        Log.d(TAG, "sendScroll dy=$dy ok=$ok")
    }

    companion object {
        private const val TAG = "FlyMouse"
        private const val REPORT_ID_MOUSE = 1
        const val ACTION_START = "START"
        const val ACTION_MOVE = "MOVE"
        const val ACTION_CLICK_LEFT = "CLICK_LEFT"
        const val ACTION_CLICK_RIGHT = "CLICK_RIGHT"
        const val ACTION_SCROLL = "SCROLL"
        const val ACTION_CONNECT_DEFAULT = "CONNECT_DEFAULT"
        const val KEY_DX = "dx"
        const val KEY_DY = "dy"

        private val REPORT_DESC_INT = intArrayOf(
            0x05, 0x01,             // Usage Page (Generic Desktop)
            0x09, 0x02,             // Usage (Mouse)
            0xA1, 0x01,             // Collection (Application)
            0x85, 0x01,             //   Report ID (1)
            0x09, 0x01,             //   Usage (Pointer)
            0xA1, 0x00,             //   Collection (Physical)
            0x05, 0x09,             //     Usage Page (Buttons)
            0x19, 0x01,             //     Usage Minimum (01)
            0x29, 0x03,             //     Usage Maximum (03)
            0x15, 0x00,             //     Logical Minimum (0)
            0x25, 0x01,             //     Logical Maximum (1)
            0x95, 0x03,             //     Report Count (3)
            0x75, 0x01,             //     Report Size (1)
            0x81, 0x02,             //     Input (Data,Var,Abs) - Buttons
            0x95, 0x01,             //     Report Count (1)
            0x75, 0x05,             //     Report Size (5)
            0x81, 0x03,             //     Input (Const,Var,Abs) - Padding
            0x05, 0x01,             //     Usage Page (Generic Desktop)
            0x09, 0x30,             //     Usage (X)
            0x09, 0x31,             //     Usage (Y)
            0x15, 0x81,             //     Logical Minimum (-127)
            0x25, 0x7F,             //     Logical Maximum (127)
            0x75, 0x08,             //     Report Size (8)
            0x95, 0x02,             //     Report Count (2)
            0x81, 0x06,             //     Input (Data,Var,Rel) - X,Y
            0x09, 0x38,             //     Usage (Wheel)
            0x15, 0x81,             //     Logical Minimum (-127)
            0x25, 0x7F,             //     Logical Maximum (127)
            0x75, 0x08,             //     Report Size (8)
            0x95, 0x01,             //     Report Count (1)
            0x81, 0x06,             //     Input (Data,Var,Rel) - Wheel
            0xC0,                   //   End Collection
            0xC0                    // End Collection
        )
        val HID_REPORT_DESC: ByteArray = REPORT_DESC_INT.map { it.toByte() }.toByteArray()
    }
}
